﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using GigaSite.Domain.Entities;
using GigaSite.Domain.Enums;
using GigaSite.Domain.Infrastucture.Misc;
using GigaSite.Domain.Interfaces.Repositories;
using GigaSite.Domain.IoC;
using GigaSite.Web.Classes;
using GigaSite.Web.Models;
using GigaSite.Web.Models.Validators;

namespace GigaSite.Web.Controllers
{
    /// <summary>
    /// Контроллер обрабатывающий весь функционал, связанный с пользовательскими аккаунтами
    /// </summary>
    public class AccountController : BaseController
    {
        #region Авторизация и регистрация

        /// <summary>
        /// Проверяет свободность определенного имени пользователя
        /// </summary>
        /// <returns>true если свободно, false если занято</returns>
        public ActionResult CheckUserName()
        {
            var repository = Locator.GetService<IUsersRepository>();
            var username = Request.Form[0];
            return Content((repository.GetUserByIdentity(username) == null).ToString());
        }
        
        /// <summary>
        /// Отображает страницу регистрации нового пользователя
        /// </summary>
        /// <returns></returns>
        public ActionResult Register()
        {
            return PartialView(new RegisterModel()
                            {
                                Gender = UserGender.DontKnow
                            });
        }

        /// <summary>
        /// Обрабатывает запрос на регистрацию пользователя
        /// </summary>
        /// <param name="model">Модель данных о регистрации пользователя</param>
        /// <returns>Сообщение об успешной регистрации или о ее неуспехе</returns>
        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            // Валидируем форму
            if (ModelState.IsValid)
            {
                // Логическая валидация
                IModelValidator<RegisterModel> validator = ModelValidatorsFactory.GetValidator<RegisterModel>();
                var errors = validator.Validate(model);
                if (errors.Count > 0)
                {
                    return ViewWithModelErrors("Register",errors, model);
                }

                // Создаем нового пользователя
                var repository = Locator.GetService<IUsersRepository>();
                var newUser = repository.RegisterUser(model.UserName, model.Email, model.Password);
                newUser.Birthday = model.Birthday;
                newUser.Gender = model.Gender;
                repository.SubmitChanges();

                // Авторизируем пользователя
                AuthorizeUser(newUser,true);
                newUser.LastLogin = DateTime.Now;
                repository.SubmitChanges();

                // Переходим на главную
                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }

        /// <summary>
        /// Отображает простую форму авторизации на сайте
        /// </summary>
        /// <returns></returns>
        public ActionResult LogOn()
        {
            return PartialView(new LogOnModel());
        }

        /// <summary>
        /// Обрабатывает запрос пользователя на заход на сайт
        /// </summary>
        /// <param name="model">Модель логина</param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult LogOn(LogOnModel model)
        {
            if (ModelState.IsValid)
            {
                // Валидируем
                var validator = ModelValidatorsFactory.GetValidator<LogOnModel>();
                var errors = validator.Validate(model);

                if (errors.Count > 0)
                {
                    return ViewWithModelErrors("LogOn", errors, model);
                }
                
                // Авторизуем пользователя
                var repository = Locator.GetService<IUsersRepository>();
                var user = repository.GetUserByIdentity(model.UserName);
                
                AuthorizeUser(user,!model.DontRememberMe);
                user.LastLogin = DateTime.Now;
                repository.SubmitChanges();

                // Переходим на главную
                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }

        /// <summary>
        /// Регистрирует или авторизует пользователя по информации из социальных сетей
        /// </summary>
        /// <param name="token">Токен авторизации для логинзы</param>
        /// <returns>Перенаправляет на главную страницу сайта</returns>
        [HttpPost]
        public ActionResult LoginSocial(string token)
        {
            // Пытаемся извлечь авторизационные данные пользователя
            if (!string.IsNullOrWhiteSpace(token))
            {
                // Коннектимся к логинзе и получаем авторизационные данные по токену
                var request = WebRequest.Create(string.Format("http://loginza.ru/api/authinfo?token={0}", token));
                var response = request.GetResponse();
                var stream = response.GetResponseStream();
                if (stream != null)
                {
                    var sr = new StreamReader(stream);
                    string jsonString = sr.ReadToEnd();

                    // Используем динамический JSON для парсинга
                    dynamic jsonObject = new DynamicJsonObject(jsonString);

                    // Валидируем
                    if (jsonObject.error_type != null)
                    {
                        // TODO: произошли какие то траблы при авторизации, надо добавить в лог и вывести пользователю сообщение о беде
                    }
                    else
                    {
                        // Успешно авторизовались
                        // Ищем пользователя в БД
                        var repository = Locator.GetService<IUsersRepository>();
                        string identity = jsonObject.identity;
                        var user = repository.GetUserByIdentity(identity);

                        if (user == null)
                        {
                            // Регистрируем пользователя по его данным из социальных сетей
                            user = repository.RegisterUser(jsonString);
                            // TODO: добавить нотифицирование о регистрации и логирование
                        }
                        else
                        {
                            // Тут нужно обновить данные о пользователе из соц сети т.к. его профиль мог поменяться
                            repository.UpdateUserSocialData(user, jsonString);
                        }
                        repository.SubmitChanges();

                        // Авторизуем пользователя
                        AuthorizeUser(user);
                        user.LastLogin = DateTime.Now;
                        repository.SubmitChanges();
                    }
                }
            }
            // Отправляем пользователя на главную
            return RedirectToAction("Index", "Home");
        }

        /// <summary>
        /// Закрывает авторизацию текущего пользователя
        /// </summary>
        /// <returns></returns>
        public ActionResult LogOff()
        {
            CloseAuthorization();
            return RedirectToAction("Index", "Home");
        }

        #endregion

        #region Подписка

        public ActionResult Subscription()
        {
            return View();
        }

        #endregion

        /// <summary>
        /// Отображает страницу с сообщениями пользователя
        /// </summary>
        /// <returns></returns>
        public ActionResult Messages()
        {
            return View();
        }

        /// <summary>
        /// Отображает страницу  со списком магазинов, которые пользователь зарегистрировал в системе
        /// </summary>
        /// <returns></returns>
        public ActionResult Shops()
        {
            return View();
        }

        /// <summary>
        /// Отображает страницу  со списком объявлений, которые подал пользователь
        /// </summary>
        /// <returns></returns>
        public ActionResult Ads()
        {
            return View();
        }

        /// <summary>
        /// Отображает страницу управления списком друзей пользователя
        /// </summary>
        /// <returns></returns>
        public ActionResult Friends()
        {
            return View();
        }

        /// <summary>
        /// Отображает страницу с настройками аккаунта
        /// </summary>
        /// <returns></returns>
        public ActionResult Settings()
        {
            return View();
        }

        #region Визитница

        /// <summary>
        /// Отображает страницу с добавлеными визитками
        /// </summary>
        /// <param name="currentPage">Страница которую отобразить</param>
        /// <param name="itemsPerPage">Количество элементов выводимых на странице</param>
        /// <param name="filterLetter">Фильтровать ли по букве</param>
        /// <returns></returns>
        public ActionResult Cards(int currentPage = 0, int itemsPerPage = 12, string filterLetter = "")
        {
            // Если пользователя нет, то нечего нам тут делать
            if (CurrentUser == null)
            {
                return RedirectToAction("Index", "Home");
            }

            // Репозиторий
            var repository = Locator.GetService<IBusinessCardsRepository>();

            // Получаем карточки которые добавлены пользователю в визитницу
            var allCards =
                CurrentUser.BusinessCardToUserMappings.Where(m => m.BusinessCard.Status == BusinessCardStatuses.Active).
                    Select(c => c.BusinessCard);

            // NOTE: Возможно тут надо будет оптимизировать механизм получения количества визиток
            var allCardsUnfiltred = allCards.Count();
            if (!String.IsNullOrEmpty(filterLetter))
            {
                allCards = allCards.Where(c => c.Title.ToUpper().StartsWith(filterLetter));
            }
            if (currentPage > 0)
            {
                allCards = allCards.Skip(currentPage * itemsPerPage).Take(itemsPerPage);
            }

            // Получаем основные сведения
            ViewBag.totalCardsCount = allCards.Count();
            ViewBag.totalCardsUnfiltredCount = allCardsUnfiltred;
            ViewBag.companyCardsCount = allCards.Count(c => c.HolderType == BusinessCardHolderTypes.Company);
            ViewBag.personalCardsCount = allCards.Count(c => c.HolderType == BusinessCardHolderTypes.Personal);
            
            // Передаем данные для фильтра
            ViewBag.currentPage = currentPage;
            ViewBag.itemsPerPage = itemsPerPage;
            ViewBag.filterLetter = filterLetter;

            // Отдаем результат
            return View();
        }

        /// <summary>
        /// Возвращает карточки по указанному запросу
        /// </summary>
        /// <param name="filter">Тип фильтра</param>
        /// <param name="currentPage">Номер текущей страницы</param>
        /// <param name="itemsPerPage">Количество карточек на страницы</param>
        /// <param name="filterLetter">Фильтр по букву</param>
        /// <returns></returns>
        public ActionResult BusinessCards(string filter, string filterLetter = null, int currentPage = 0, int itemsPerPage = 12)
        {
            if (CurrentUser == null)
            {
                return Content("Пользователь не авторизован");
            }
            
            // Репозиторий
            var repository = Locator.GetService<IBusinessCardsRepository>();
            bool needToSort = true, needToPage = true;

            // Получаем визитки в зависимости от фильтра
            IEnumerable<BusinessCard> dbCards =
                CurrentUser.BusinessCardToUserMappings.Where(m => m.BusinessCard.Status == BusinessCardStatuses.Active).
                    Select(m => m.BusinessCard);
            switch (filter)
            {
                case "company":
                    // визитки компаний
                    dbCards = dbCards.Where(c => c.HolderType == BusinessCardHolderTypes.Company);
                    break;
                case "specialist":
                    // визитки специалистов
                    dbCards = dbCards.Where(c => c.HolderType == BusinessCardHolderTypes.Personal);
                    break;
            }

            // Дополнительно фильтруем
            if (!String.IsNullOrEmpty(filterLetter))
            {
                dbCards = dbCards.Where(c => c.Title.StartsWith(filterLetter));
            }

            // Сортируем
            if (needToSort)
                dbCards = dbCards.OrderBy(c => c.Title);

            // Пейджионируем
            if (needToPage)
                dbCards = dbCards.Skip(currentPage * itemsPerPage).Take(itemsPerPage);

            // Преобразуем в модели
            var cards = dbCards.Select(c => new BusinessCardModel(c));

            // Отдаем партиал вью
            return PartialView("CardsGrid", cards);
        }

        /// <summary>
        /// Обрабатывает запрос на добавление визитки в визитницу пользователя
        /// </summary>
        /// <param name="id">Идентификатор визитки</param>
        /// <returns>Json success</returns>
        [HttpPost]
        public JsonResult AddCard(long id)
        {
            // Проверяем что у нас есть пользователь
            if (CurrentUser == null)
            {
                return JsonError("Пользователь не авторизован");
            }
            
            // Репозиторий
            var repository = Locator.GetService<IBusinessCardsRepository>();

            // Загружаем визитку
            var card = repository.Load(id);
            if (card == null)
            {
                return JsonError(string.Format("Визитка с идентификатором {0} не найдена", id));
            }

            // Добавляет ее в визитницу
            repository.AddBusinessCardToUser(CurrentUser,card);
            repository.SubmitChanges();

            // Отадем результат
            return JsonSuccess();
        }

        /// <summary>
        /// Удаляет указанную визитку из визитницы пользователя
        /// </summary>
        /// <param name="id">Идентификатор визитки</param>
        /// <returns>Json succes</returns>
        [HttpPost]
        public JsonResult RemoveCard(long id)
        {
            // Проверяем что у нас есть пользователь
            if (CurrentUser == null)
            {
                return JsonError("Пользователь не авторизован");
            }

            // Репозиторий
            var repository = Locator.GetService<IBusinessCardsRepository>();

            // Загружаем визитку
            var card = repository.Load(id);
            if (card == null)
            {
                return JsonError(string.Format("Визитка с идентификатором {0} не найдена", id));
            }

            // Добавляет ее в визитницу
            repository.RemoveBusinessCardFromUser(CurrentUser, card);
            repository.SubmitChanges();

            // Отадем результат
            return JsonSuccess();
        }

        #endregion
    }
}
